package copy.code;


import com.sun.source.tree.Tree;
import com.sun.source.util.TreePath;
import com.sun.tools.javac.api.JavacTrees;
import com.sun.tools.javac.tree.JCTree;
import com.sun.tools.javac.tree.TreeMaker;
import com.sun.tools.javac.util.List;
import com.sun.tools.javac.util.Names;
import copy.application.Process;
import copy.exception.MethodParamException;
import copy.tools.StringStrTools;

import javax.annotation.processing.ProcessingEnvironment;
import javax.lang.model.element.Element;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.Queue;

/**
 * 类作用: 操作字节码最基本的方法
 */
public abstract class AbsClassCode implements Process {
    protected JavacTrees javacTrees;
    protected TreeMaker treeMaker;
    protected Names names;

    public AbsClassCode(ProcessingEnvironment processingEnv) {
        this.javacTrees = javacTrees;
        this.treeMaker = treeMaker;
        this.names = names;
    }

    protected JCTree.JCVariableDecl getVariableByParams(List<JCTree.JCVariableDecl> variableDeclList, String variableName){
        for (JCTree.JCVariableDecl v : variableDeclList) {
            if (v.getName().toString().equals(variableName)){
                return v;
            }
        }
        return null;
    }
    /**
     *
     * @param element
     * @param TRACKER_PACKAGE
     * @param CLASS_NAME
     */
    protected void addImportInfo(Element element,String TRACKER_PACKAGE,String CLASS_NAME) {
        TreePath treePath = javacTrees.getPath(element);
        Tree leaf = treePath.getLeaf();
        if (treePath.getCompilationUnit() instanceof JCTree.JCCompilationUnit && leaf instanceof JCTree) {
            JCTree.JCCompilationUnit jccu = (JCTree.JCCompilationUnit) treePath.getCompilationUnit();

            for (JCTree jcTree : jccu.getImports()) {
                if (jcTree != null && jcTree instanceof JCTree.JCImport) {
                    JCTree.JCImport jcImport = (JCTree.JCImport) jcTree;
                    if (jcImport.qualid != null && jcImport.qualid instanceof JCTree.JCFieldAccess) {
                        JCTree.JCFieldAccess jcFieldAccess = (JCTree.JCFieldAccess) jcImport.qualid;
                        try {
                            if (TRACKER_PACKAGE.equals(jcFieldAccess.selected.toString()) && CLASS_NAME.equals(jcFieldAccess.name.toString())) {
                                return;
                            }
                        } catch (NullPointerException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
            java.util.List<JCTree> trees = new ArrayList<>();
            trees.addAll(jccu.defs);
            JCTree.JCIdent ident = treeMaker.Ident(names.fromString(TRACKER_PACKAGE));
            JCTree.JCImport jcImport = treeMaker.Import(treeMaker.Select(
                    ident, names.fromString(CLASS_NAME)), false);
            if (!trees.contains(jcImport)) {
                trees.add(0, jcImport);
            }
            jccu.defs = List.from(trees);
        }
    }

    public JCTree.JCExpressionStatement setField(String fileName,JCTree.JCMethodDecl method,JCTree.JCExpression valueExpression){
        String[] split = fileName.split("\\.");
        JCTree.JCExpression express = getParamExpressByStrName(fileName, method);
        return doSetField(genQueueByArray(split),express,valueExpression);
    }

    public JCTree.JCExpression getParamExpressByStrName(String fileName,JCTree.JCMethodDecl method){
        String[] split = fileName.split("\\.");
        //获取参数列表: 开始解析student.name
        JCTree.JCExpressionStatement getVariableStatement = null;
        for (JCTree.JCVariableDecl parameter : method.getParameters()) {
            if (split.length>0 &&parameter.getName().toString().equals(split[0])){
                return treeMaker.Ident(parameter);

            }
        }
        throw new MethodParamException(method.getName().toString(),fileName);
    }

    public JCTree.JCExpressionStatement getField(String fileName,JCTree.JCMethodDecl method){
        String[] split = fileName.split("\\.");
        JCTree.JCExpression express = getParamExpressByStrName(fileName, method);
        //生成队列
        return  doGetField(genQueueByArray(split), express, method);

    }

    public JCTree.JCExpressionStatement doGetField(Queue<String> queue, JCTree.JCExpression jcExpression, JCTree.JCMethodDecl methodDecl){
        String fieldName = queue.poll();
        //JCTree.JCVariableDecl parameter = null;
        JCTree.JCExpressionStatement exec1 = treeMaker.Exec(
                treeMaker.Apply(
                        com.sun.tools.javac.util.List.nil(),
                        treeMaker.Select(
                                jcExpression, // . 左边的内容
                                names.fromString( StringStrTools.genStr(StringStrTools.GET,fieldName)  ) // . 右边的内容
                        ),
                        com.sun.tools.javac.util.List.nil()
                )
        );
        //添加语句到方法体中
        if (queue.size()>0){
            //递归
            return doGetField(queue,exec1.expr,methodDecl);
        }
        return exec1;
    }

    public JCTree.JCExpressionStatement doSetField(Queue<String> queue,JCTree.JCExpression rootVariableExpress,JCTree.JCExpression resExpression){
        String fieldName = queue.poll();
        int size = queue.size();
        if ( size != 0 ){
            JCTree.JCExpressionStatement resExpr = treeMaker.Exec(
                    treeMaker.Apply(
                            List.nil(),
                            treeMaker.Select(
                                    rootVariableExpress, // . 左边的内容
                                    names.fromString(StringStrTools.genStr(StringStrTools.GET, fieldName)) // . 右边的内容
                            ),
                            List.nil()
                    )
            );
            //递归
            return doSetField(queue,resExpr.expr,resExpression);
        }else{
            String methodName = StringStrTools.genStr(StringStrTools.SET, fieldName);
            return  treeMaker.Exec(
                    treeMaker.Apply(
                            com.sun.tools.javac.util.List.nil(),
                            treeMaker.Select(
                                    rootVariableExpress, // . 左边的内容
                                    names.fromString( methodName  ) // . 右边的内容
                            ),
                            com.sun.tools.javac.util.List.of(resExpression)
                    )
            );
        }
    }


    public Queue<String> genQueueByArray(String[] spit){
        Queue<String> queue = new LinkedList();
        for (int i = 1; i < spit.length; i++) {
            queue.add(spit[i]);
        }
        return queue;
    }

    //com.sun.tools.javac.util.List.of(treeMaker.Ident(targetVariableDecl.getName()), treeMaker.Ident(resourceVariableDecl.getName())) // 方法中的内容
    public JCTree.JCExpressionStatement doExeMethodByClassName(String className,String methodName,List argsList){
        return doExeMethod(treeMaker.Ident(names.fromString(className)),methodName,argsList);

    }
    public JCTree.JCExpressionStatement doExeMethod(JCTree.JCExpression expression,String methodName,List argsList){
        JCTree.JCExpressionStatement exec2 = treeMaker.Exec(
                treeMaker.Apply(
                        com.sun.tools.javac.util.List.nil(),
                        treeMaker.Select(
                                expression, // . 左边的内容
                                names.fromString(methodName) // . 右边的内容
                        ),argsList
                )
        );
        return exec2;

    }
}
